package com.tizona.service.impl;

import com.tizona.TarifdConfig;
import com.tizona.dao.jdbc.FastStatement;
import com.tizona.service.ServiceManager;
import com.tizona.service.SessionManager;
import com.tizona.service.TarifManager;
import com.tizona.entity.tarification.Parameter;
import com.tizona.service.tarification.Restriction;
import com.tizona.entity.Lc;
import com.tizona.entity.Se;
import com.tizona.entity.SeProp;

import java.util.HashSet;
import java.util.Calendar;
import java.util.Set;
import java.util.Map;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Timestamp;

/**
 * Created by Vitaliy Kim. 
 * Date: 23.08.2005
 * Time: 22:21:10
 */
public class ServiceManagerImpl extends BaseManager implements ServiceManager {

    private TarifdConfig cfg;
    private FastStatement fstmt1, fstmtProps, fstmtPropsCreate
            , fstmtUpdatePermissions, fstmtPropsUpdate;

    public ServiceManagerImpl(TarifdConfig cfg) throws SQLException {
        this.cfg = cfg;

        fstmt1 = cfg.sql.prepare(
                "SELECT SE_ID, SVC_ID, LOGIN, TP_ID,"+
                        " QT_ID,AUTO,ACTIVITY from SE WHERE SE.LC_Num=? AND DELETED=0");

        fstmtProps = cfg.sql.prepare("SELECT NAME,VALUE,DATE FROM SE_PROPS WHERE SE_ID=?");

        fstmtPropsUpdate = cfg.sql.prepare("update SE_PROPS set VALUE = ?,DATE=? WHERE NAME=? and SE_ID=?");

        fstmtPropsCreate = cfg.sql.prepare("insert SE_PROPS (SE_ID,NAME,VALUE,DATE) values(?,?,?,?)");

        fstmtUpdatePermissions = cfg.sql.prepare("UPDATE SE SET AUTO=?, ACTIVITY = ? WHERE SE_ID=?");
    }

    /**
     *
     * @param lc
     * @param model_time
     * @return  Set of Services for Contract
     */
    public HashSet <Se> getActiveServices(Lc lc, Calendar model_time) {

        HashSet <Se> services = new HashSet <Se> ();
        SessionManager mgr = cfg.sessionMan;

        try {
            fstmt1.setLong(1, lc.getLcNum());
            ResultSet se_res = cfg.sql.query(fstmt1);

            while(se_res.next())
            {
                Se se=new Se(se_res.getLong("SE_ID")
                        ,se_res.getBoolean("AUTO")
                        ,se_res.getShort("ACTIVITY")
                        ,se_res.getLong("SVC_ID")
                        ,se_res.getLong("TP_ID"),
                        se_res.getLong("QT_ID"));

                mgr.createStructureOfSession(se, model_time);

                se.setLc(lc);

                services.add(se);
            }

        } catch (SQLException e) {
            log.error(e.getMessage());
        }
        return services;
    }


    /**
     * For passive execution throught the Web interface
     * @param lc
     * @param model_time
     * @return Ses
     */
    public HashSet <Se> getServices(Lc lc, Calendar model_time) {

        HashSet <Se> services = new HashSet <Se> ();

        try {
            fstmt1.setLong(1, lc.getLcNum());
            ResultSet se_res = cfg.sql.query(fstmt1);

            while(se_res.next())
            {
                Se se=new Se(se_res.getLong("SE_ID")
                        ,se_res.getBoolean("AUTO")
                        ,se_res.getShort("ACTIVITY")
                        ,se_res.getLong("SVC_ID")
                        ,se_res.getLong("TP_ID"),
                        se_res.getLong("QT_ID"));

                se.setLc(lc);

                services.add(se);
            }

        } catch (SQLException e) {
            log.error(e.getMessage());
        }
        return services;
    }

    public void process(Set <Se> services, final Calendar modelTime) {
        SessionManager sessionmgr = cfg.sessionMan;
        TarifManager tarifmgr = cfg.tarifMan;

        Restriction rest = null;
        Lc lc = null;

        for(Se se:services) {
            try {
                loadParams(se);

                Restriction restrict = tarifmgr.getRestriction(se.getQuote().toString());
                restrict.setManager(cfg.contractMan);

                if(se.getSvc() == 3l && rest == null) {
                    rest = restrict;
                    lc = se.getLc();
                }

                if(se.getLc().getLcProps().get("ABON_TIME") == null) {
                    //Process tarification SE untill session tarification, because need to define copy params

                    sessionmgr.loadSessions(se);
                    restrict.process(se, modelTime);
                }

                //Tarification substructures
                sessionmgr.process(se, tarifmgr.getTarification(se.getTarif().toString()), modelTime);

                //Access restrictions
                restrict.process(se, modelTime);

                if(se.isUpdated()) {
                    log.debug("Se permission changed SE_ID: " + se.getSeId() + " - " + se.isAuto());
                    updatePermisions(se);
                }

                updateParams(se);
                log.debug("Update accums");
            } catch (Exception e) {
                e.printStackTrace();
                log.fatal(e);
            }
        }

        // to check LC access restrictions (exp_abon_time & setInvoice)
        try {
            if(rest != null && lc != null) {
                rest.process(lc, modelTime);
                for(Se se : lc.getSes()) {
                    if(se.isUpdated()) {
                        log.debug("Se permission changed SE_ID: " + se.getSeId() + " - " + se.isAuto());
                        updatePermisions(se);
                    }
                }
            }
            else
                log.info("either LC or restriction is null");
        }
        catch (Exception ex) {
            ex.printStackTrace();
            log.error("Error during rest.process(lc, calendar): " + ex.getMessage());
        }

    }

    private void loadParams(Se se) throws SQLException{
        fstmtProps.setLong(1, se.getSeId());
         SeProp seprop;
        for(ResultSet resultset = cfg.sql.query(fstmtProps); resultset.next(); se.getSeProps().put(resultset.getString("NAME"), seprop)) {
            log.debug("Load SE param: " + resultset.getString("NAME"));

            if(resultset.getString("VALUE") != null)
                seprop = new SeProp(resultset.getString("VALUE"));
            else
                seprop = new SeProp(resultset.getTimestamp("DATE"));
        }
    }

    private void updateParams(Se se) throws SQLException {

        for(Map.Entry element:se.getSeProps().entrySet()) {
            Parameter prop = (Parameter) element.getValue();
            if(prop.isChanged()) {
                String key = (String) element.getKey();
                if(prop.isCreate()) {
                    fstmtPropsCreate.setLong(1, se.getSeId());
                    fstmtPropsCreate.setString(2, key);
                    fstmtPropsCreate.setString(3, prop.asString());
                    fstmtPropsCreate.setTimestamp(4, new Timestamp(prop.getDate().getTime()));
                    cfg.sql.update(fstmtPropsCreate);
                } else {
                    fstmtPropsUpdate.setString(1, prop.asString());
                    fstmtPropsUpdate.setTimestamp(2, new Timestamp(prop.getDate().getTime()));
                    fstmtPropsUpdate.setString(3, key);
                    fstmtPropsUpdate.setLong(4, se.getSeId());
                    cfg.sql.update(fstmtPropsUpdate);
                }

            }
        }
    }

    private void updatePermisions(Se se) throws SQLException {
        fstmtUpdatePermissions.setBoolean(1, se.isAuto());
        fstmtUpdatePermissions.setInt(2, se.getActivity());
        fstmtUpdatePermissions.setLong(3, se.getSeId());

        cfg.sql.update(fstmtUpdatePermissions);
    }

}